package cmd;
import java.util.*;
import java.io.*;
//class - component of processing data

public class Model {
	//interface for processing of input arguments
	public interface modelInterface{
		public boolean checkArgs(String[] args);
		public Object action();
	}
	static private File workDirectory;
	static private File Directory;
	static private File[] SubDirectory;
	static private String[] args;
	static private String Mask;
	
	//methods of class Model
	
	//constructor, have two arguments: the massive of splitting readLine
	//and workDirectory
	Model(String[] Str,File workDir){
		args = Str;
		workDirectory = workDir;}
	
	//method of print the content directory
	public String[] dir(){
		printContentDirectory Object = new printContentDirectory();
		if (Object.checkArgs(args)) return (String[]) Object.action();
		return null;
	}
	//method of print the tree directory
	public LinkedList<String> tree(){
		printTreeDirectory Object = new printTreeDirectory();
		if (Object.checkArgs(args)){
			@SuppressWarnings("unchecked")
			LinkedList<String> List = (LinkedList<String>) Object.action();
		return List;}
		return null;
	}
	//methods of search the needed file with using mask
	public String[] find(){
		findFileInDirectory Object = new findFileInDirectory();
		if (Object.checkArgs(args)){
			@SuppressWarnings("unchecked")
			HashSet<String> List = (HashSet<String>) Object.action();
		String ListInfo[] = new String[List.size()];
		List.toArray(ListInfo);
		return ListInfo;}
		else return null;
	}
	//method of copy the file in input directory
	public boolean copy(){
		copyFile Object = new copyFile();
		if (Object.checkArgs(args)) return (Boolean) Object.action();
		return false;
	}
	//method of move the file in input directory
	public boolean move(){
		boolean flag=false;
		copyFile copyObject = new copyFile();
		if (copyObject.checkArgs(args)){
			flag = (Boolean) copyObject.action();
			deleteDir delObject = new deleteDir();
			if (delObject.checkArgs(args)) flag =(Boolean) delObject.action();
		}
		else flag = false;
		return flag;
	}
	//method of create the new directory
	public boolean mkdir(){
		makeDirectory Object = new makeDirectory();
		if (Object.checkArgs(args)) return (Boolean) Object.action();
		else return false;
	}
	//method of change the work directory
	public File cd(){
		changeWorkDirectory Object = new changeWorkDirectory();
		if (Object.checkArgs(args)) return (File) Object.action();
		else return null;
	}
	//method of delete directory
	public boolean del(){
		deleteDir Object = new deleteDir();
		if (Object.checkArgs(args)) return (Boolean) Object.action();
		else return false;
	}
	//method for defined of type the way
	private String orAbsRel(String way){
		String newWay;
		if (!way.contains(":")){
			newWay = workDirectory.getPath()+"\\"+way;
		}
		else newWay = way;
		return newWay;
	}
	
	class printContentDirectory implements modelInterface{	
		private String[] List;
		private int countFiles=0,countDirs=0;
		public Object action(){
			SubDirectory = Directory.listFiles();
			List = new String[SubDirectory.length+1];
			for (int i=0;i<SubDirectory.length;i++) 
				{
				List[i]="";
				if (SubDirectory[i].isDirectory()) {
					List[i]+="<DIR>\t";
					countDirs++;
				}
				else {
					List[i]+="<FILE>\t";
					countFiles++;
				}
				List[i]+=SubDirectory[i].getName();
				List[i]+="\t" + new Date(SubDirectory[i].lastModified());
				}
			List[SubDirectory.length]="\t"+countDirs+" folders\n\t"+countFiles+" files";
			return List;
		}
		
		public boolean checkArgs(String[] args){
			if (args.length==1) {
				Directory = workDirectory;
				return true;
			}
			if (args.length==2) {
				Directory = new File(orAbsRel(args[1]));
			return (Directory.exists());
			}
			else return false;
		}
	}
	
	class printTreeDirectory implements modelInterface{
		private LinkedList<String> list = new LinkedList<String>();
		private File[] SubDirectory;
		public Object action(){
			contentTree(Directory,0);
			return list;
		}
		//recursive procedure for finding the contents of a directory
		private void contentTree(File Directory,int Indents)
		{
			String indents="";
			for (int i=0;i<Indents;i++) indents+="     ";
			list.add(indents);
			if (Directory.isFile()) list.add("<FILE> "+Directory.getName());
			else {
			    SubDirectory = Directory.listFiles();
				list.add("[+]<DIR> "+Directory.getName());
				methodSort();
				for (File SubWay:SubDirectory)
					contentTree(SubWay,Indents+1);
			}
		}
		//sort the massive of files, at first files and then folders
		private void methodSort(){
			LinkedList<File> dirList = new LinkedList<File>();
			LinkedList<File> files = new LinkedList<File>();
			
			for (File subDir:SubDirectory) dirList.add(subDir);
			for (int i=0;i<dirList.size();i++){
				File Obj = dirList.get(i);
				if (Obj.isFile()){
				files.add(Obj);
				dirList.remove(i);
				}
			}
			files.addAll(dirList);
			for (int j=0;j<SubDirectory.length;j++) SubDirectory[j]=files.get(j);
		}
		public boolean checkArgs(String[] args){
			printContentDirectory checkObject = new printContentDirectory();
			return checkObject.checkArgs(args);
		}
	}
	
	class findFileInDirectory implements modelInterface{
		private String findPath;
		private HashSet<String> List = new HashSet<String>();
		//recursive procedure to check the contents of a directory
		public Object action()
		{
			if (Directory.isFile()) getInfoFile(Directory,Mask);
			else {
				getInfoFile(Directory,Mask);
				File[] SubDirectory = Directory.listFiles();
				for (File SubWay:SubDirectory){
					Directory = SubWay;
					action();
				}
			}
			return List;
		}
		private void getInfoFile(File Object,String Mask){
				String Name = Object.getName();	
				if (Name.contains(Mask)) {
					List.add(Name +"\n" + Object.getPath() + "\n" 
							+ new Date(Object.lastModified())+"\n");				
				}
		}
		public boolean checkArgs(String[] args){
			
			if (args.length==2){
				Directory = workDirectory;
				Mask = args[1];
				return true;
			}
			if (args.length==3){
				if (!args[1].contains(":"))
					findPath = workDirectory.getPath()+"\\"+args[1];
				else findPath = args[1];
				Directory = new File(findPath);
				if (Directory.exists()){
					Mask = args[2];
					return true;
				}
				else return false;
			}
			else return false;
		}
	}
	
	class copyFile implements modelInterface{
		private File srcFile;
		private File dstFile;
		
		public Object action(){		
			try{		
				InputStream in = new FileInputStream(srcFile);
                OutputStream out = new FileOutputStream(dstFile);
                byte[] buf = new byte[1024];
                int length;
                while ((length = in.read(buf)) > 0){
                out.write(buf, 0, length);
                }
                in.close();
                out.close();
                return true;
			}
			catch (IOException e)
			{
				return false;
			}
		}
		public boolean checkArgs(String[] args){
			boolean flag = false;
			if (args.length==3){
				srcFile = new File(orAbsRel(args[1]));
				dstFile = new File(orAbsRel(args[2]));
				if (!srcFile.exists()) flag = false;
				if(srcFile.exists()&&!dstFile.exists()){
					try{
						flag = (dstFile.createNewFile());
					}
					catch (IOException e){flag = false;}
				}
				if (srcFile.exists()&&dstFile.exists()) flag = true;
				else flag = false;
				return flag;
			}
			return false;
		}
	}
	
	class makeDirectory implements modelInterface{
		private String Path;
		public Object action(){
			return Directory.mkdir();
		}
		public boolean checkArgs(String[] args){
			if (args.length==1) return false;
			else {
				if (!args[1].contains(":"))
					Path = workDirectory.getPath()+"\\"+args[1];
				else Path = args[1];
				Directory = new File(Path);
				return (!Directory.exists());
			}
		}
	}

	class deleteDir implements modelInterface{
		
			public Object action(){
				if (Directory.isFile()) return Directory.delete();
				else{
				while (!Directory.delete()){
					delDir(Directory);
				}
				return true;
				}
			}
			//recursive procedure for delete the all files in directory
			private void delDir(File Directory)
			{
				if (Directory.isFile()) Directory.delete();
				else {
					if (Directory.delete()){}
					else{
				    SubDirectory = Directory.listFiles();
					for (File SubWay:SubDirectory)
						delDir(SubWay);}
				}
		}
			public boolean checkArgs(String[] args){
				if (args.length==1) return false;
				else {	
					Directory = new File(orAbsRel(args[1]));
					return (Directory.exists());
				}
			}
	}
	
    class changeWorkDirectory implements modelInterface{
		public Object action() {
			return workDirectory;
		}
		public boolean checkArgs(String[] args){
			if (args.length==1) return false;
			else { 
			workDirectory = new File(orAbsRel(args[1]));
			return (workDirectory.exists());
			}
		}
	}
}


